home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / kernel / plan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-02  |  55.6 KB  |  2,386 lines  |  [TEXT/KAHL]

  1. /* Unit plan execution for Xconq.
  2.    Copyright (C) 1991, 1992, 1993, 1994, 1995 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. #include "conq.h"
  10.  
  11. static void wake_at PROTO ((int x, int y));
  12.  
  13. /* (should have a generic struct for all plan type attrs) */
  14.  
  15. char *plantypenames[] = {
  16.  
  17. #undef  DEF_PLAN
  18. #define DEF_PLAN(NAME,code) NAME,
  19.  
  20. #include "plan.def"
  21.  
  22.     NULL
  23. };
  24.  
  25. /* Execute the plan. */
  26.  
  27. void
  28. execute_plan(unit, try)
  29. Unit *unit;
  30. int try;
  31. {
  32.     Plan *plan = unit->plan;
  33.  
  34.     if (!in_play(unit) || !completed(unit)) {
  35.     DMprintf("%s shouldn't be planning yet\n", unit_desig(unit));
  36.     return; 
  37.     }
  38.     DMprintf("%s using plan %s", unit_desig(unit), plan_desig(plan));
  39.     if (try > 1)
  40.       DMprintf(" (try #%d)", try);
  41.     DMprintf("\n");
  42.     /* Units that are asleep or in reserve do nothing. */
  43.     if (plan->asleep || plan->reserve)
  44.       return;
  45.     if (try > 5) {
  46.     DMprintf("%s redoing plan too often, going into reserve\n",
  47.          unit_desig(unit));
  48.     plan->reserve = TRUE;
  49.     return;
  50.     }
  51.     /* Unit actually has a plan, dispatch on its type. */
  52.     switch (plan->type) {
  53.       case PLAN_NONE:
  54.     /* We get one chance to form a plan, putting the unit to sleep
  55.        if it doesn't work. */
  56.     decide_plan(unit->side, unit);
  57.     if (plan->type != PLAN_NONE) {
  58.         execute_plan(unit, ++try);
  59.     } else {
  60.         DMprintf("%s could not form a plan, going to sleep\n",
  61.              unit_desig(unit));
  62.         plan->asleep = TRUE;
  63.     }
  64.     break;
  65.       case PLAN_PASSIVE:
  66.     /* Passive units just work from the task queue or wait
  67.        to be told what to do. */
  68.     if (plan->supply_is_low && plan->supply_alarm) {
  69.         plan->supply_alarm = FALSE;
  70.         if (0 /* auto resupply */) {
  71.         set_resupply_task(unit);
  72.         } else if (plan->tasks
  73.                    && (plan->tasks->type == TASK_RESUPPLY
  74.                        || (plan->tasks->type == TASK_MOVETO
  75.                            && plan->tasks->next
  76.                            && plan->tasks->next->type == TASK_RESUPPLY))) {
  77.         /* do nothing */
  78.         } else {           
  79.         clear_task_agenda(plan);
  80.         wait_for_orders(unit);
  81.         }
  82.     }
  83.     if (plan->tasks) {
  84.         /* (should check that doctrine being followed correctly) */
  85.         execute_task(unit);
  86.     } else if (plan->formation && move_into_formation(unit)) {
  87.         execute_task(unit);
  88.     } else if (plan->autotask) {
  89.         decide_tasks(unit);
  90.         execute_plan(unit, ++try);
  91.     } else if (unit->side && side_has_ai(unit->side)) {
  92.         /* Give AI a chance to dream up a more interesting plan. */
  93.         decide_plan(unit->side, unit);
  94.         execute_plan(unit, ++try);
  95.     } else if (doctrine_allows_wait(unit)) {
  96.         /* Our goal is now to get guidance from the side. */
  97.         wait_for_orders(unit);
  98.     } else {
  99.         /* We just are not getting any guidance at all... */
  100.         DMprintf("%s passive plan not working, going to sleep\n",
  101.              unit_desig(unit));
  102.         plan->asleep = TRUE;
  103.     }
  104.     break;
  105.       case PLAN_OFFENSIVE:
  106.     plan_offense(unit);
  107.     break;
  108.       case PLAN_DEFENSIVE:
  109.     plan_defense(unit);
  110.     break;
  111.       case PLAN_EXPLORATORY:
  112.     plan_exploration(unit);
  113.     break;
  114.       case PLAN_RANDOM:
  115.     plan_random(unit);
  116.     break;
  117.       default:
  118.     case_panic("plan type", plan->type);
  119.     break;
  120.     }
  121. }
  122.  
  123. /* See if we're too far away from an assigned position, set a task
  124.    to move back if so. */
  125.  
  126. int
  127. move_into_formation(unit)
  128. Unit *unit;
  129. {
  130.     int nx, ny, dist; 
  131.     Plan *plan = unit->plan;
  132.     Goal *goal;
  133.     Unit *leader;
  134.  
  135.     leader = plan->funit;
  136.     /* (should doublecheck against leader id) */
  137.     if (leader != NULL) {
  138.     goal = plan->formation;
  139.     nx = leader->x + goal->args[1];  ny = leader->y + goal->args[2];
  140.     dist = goal->args[3];
  141.     if (distance(unit->x, unit->y, nx, ny) > dist) {
  142.         /* (should perhaps insert after current task?) */
  143.         set_movenear_task(unit, nx, ny, dist);
  144.         return TRUE;
  145.     }
  146.     }
  147.     return FALSE;
  148. }
  149.  
  150. /* A unit operating offensively advances and attacks when possible. */
  151.  
  152. void
  153. plan_offense(unit)
  154. Unit *unit;
  155. {
  156.     int u = unit->type;
  157.     int x, y, w, h, range, x1, y1;
  158.     Plan *plan = unit->plan;
  159.  
  160.     if (resupply_if_low(unit))
  161.       return;
  162.     if (rearm_if_low(unit))
  163.       return;
  164.     if (plan->tasks) {
  165.         execute_task(unit);
  166.         return;
  167.     }
  168.     if (plan->maingoal && mobile(u)) {
  169.     switch (plan->maingoal->type) {
  170.       case GOAL_VICINITY_HELD:
  171.         x = plan->maingoal->args[0];  y = plan->maingoal->args[1];
  172.         w = plan->maingoal->args[2];  h = plan->maingoal->args[3];
  173.         if (distance(x, y, unit->x, unit->y) > max(w, h)) {
  174.         /* Outside the goal area - move in towards it. */
  175.             if (random_point_near(x, y, w / 2, &x1, &y1)) {
  176.             x = x1;  y = y1;
  177.             }
  178.         DMprintf("%s to go on offensive to %d,%d\n",
  179.              unit_desig(unit), x, y);
  180.         push_movenear_task(unit, x, y, max(w, h) / 2);
  181.         if (unit->transport
  182.             && mobile(unit->transport->type)
  183.             && unit->transport->plan) {
  184.             push_movenear_task(unit->transport, x, y, max(w, h) / 2);
  185.         }
  186.         } else {
  187.         range = max(w, h);
  188.         /* No special goal, look for something to fight with. */
  189.         /* Sometimes be willing to look a little farther out. */
  190.         if (probability(50))
  191.           range *= 2;
  192.         if (do_for_occupants(unit)) {
  193.         } else if (go_after_victim(unit, range)) {
  194.         } else if (probability(20) && self_build_base_for_self(unit)) {
  195.         } else if (!g_see_all()) {
  196.             DMprintf("%s will explore instead\n", unit_desig(unit));
  197.             plan_exploration(unit); /* or patrol */
  198.             /* Running under exploration rules now. */
  199.             return;
  200.         }
  201.         }
  202.         break;
  203.       default:
  204.         DMprintf("offensive unit has some goal\n");
  205.         break;
  206.     }
  207.     } else if (mobile(u)) {
  208.     range = operating_range_best(u);
  209.     if (probability(50))
  210.       range = min(range, 2 * u_acp(u));
  211.     if (do_for_occupants(unit)) {
  212.     } else if (go_after_victim(unit, range)) {
  213.         /* No special goal, but found something to fight with. */
  214.     } else if (!g_see_all()) {
  215.         DMprintf("%s will explore instead\n", unit_desig(unit));
  216.         plan_exploration(unit); /* or patrol */
  217.         /* Running under exploration rules now. */
  218.         return;
  219.     } else {
  220.         /* should go to a "best location" if possible. */
  221.         /* (should do a sentry task) */
  222.     }
  223.     } else if (can_fire(unit) && fire_at_opportunity(unit)) {
  224.     } else {
  225.     plan_offense_support(unit);
  226.     }
  227.     if (plan->tasks) {
  228.         execute_task(unit);
  229.     } else {
  230.         DMprintf("%s found nothing to do offensively", unit_desig(unit));
  231.         if (flip_coin()) {
  232.             DMprintf("- going into reserve");
  233.             plan->reserve = TRUE;
  234.         } else if (probability(5)) {
  235.             DMprintf("- going to sleep");
  236.             plan->asleep = TRUE;
  237.         }
  238.         DMprintf("\n");
  239.     }
  240. }
  241.  
  242. int
  243. do_for_occupants(unit)
  244. Unit *unit;
  245. {
  246.     Unit *occ;
  247.     Goal *goal;
  248.     Task *task;
  249.  
  250.     for_all_occupants(unit, occ) {
  251.     if (occ->plan) {
  252.         /* Get the unit towards its goal, if it has one. */
  253.         if ((goal = occ->plan->maingoal) != NULL
  254.         && goal->type == GOAL_VICINITY_HELD
  255.         && distance(goal->args[0], goal->args[1], unit->x, unit->y)
  256.         > goal->args[2]) {
  257.         set_movenear_task(unit, goal->args[0], goal->args[1],
  258.                   max(goal->args[2] / 2, 1));
  259.         DMprintf("%s will go where occupant %s wants to go (goal %s)\n",
  260.              unit_desig(unit), unit_desig(occ), goal_desig(goal));
  261.         return TRUE;
  262.         }
  263.         /* If the unit does not have a goal, see if it has a task. */
  264.         for (task = occ->plan->tasks; task != NULL; task = task->next) {
  265.         if ((task->type == TASK_MOVETO
  266.              || task->type == TASK_HIT_UNIT)
  267.             && (task->args[0] != unit->x
  268.             || task->args[1] != unit->y)
  269.             && distance(task->args[0], task->args[1], unit->x, unit->y) > 1
  270.             ) {
  271.             set_movenear_task(unit, task->args[0], task->args[1], 1);
  272.             DMprintf("%s will go where occupant %s wants to go (task %s)\n",
  273.                  unit_desig(unit), unit_desig(occ), task_desig(task));
  274.             return TRUE;
  275.         }
  276.         }
  277.     }
  278.     }
  279.     return FALSE;
  280. }
  281.  
  282. int
  283. self_build_base_for_self(unit)
  284. Unit *unit;
  285. {
  286.     int u = unit->type, u2, cando = FALSE;
  287.  
  288.     for_all_unit_types(u2) {
  289.     if (uu_acp_to_create(u, u2) > 0
  290.         && (uu_creation_cp(u, u2) >= u_cp(u2)
  291.             || uu_acp_to_build(u, u2) > 0)
  292.         /* (should check if any advantage to building) */
  293.        ) {
  294.        cando = TRUE;
  295.        break;
  296.     }
  297.     }
  298.     if (cando) {
  299.     DMprintf("%s building %s as a base for itself\n",
  300.              unit_desig(unit), u_type_name(u2));
  301.     set_construction(unit, u2, 1);
  302.     return TRUE;
  303.     }
  304.     return FALSE;
  305. }
  306.  
  307. void
  308. plan_offense_support(unit)
  309. Unit *unit;
  310. {
  311.     int u = unit->type, u2, u3 = NONUTYPE, backup = NONUTYPE;
  312.     Task *task;
  313.  
  314.     if (side_has_ai(unit->side)) {
  315.     u3 = ai_preferred_build_type(unit->side, unit, PLAN_OFFENSIVE);
  316.     } else {
  317.     for_all_unit_types(u2) {
  318.         if (mobile(u2)
  319.         && (type_can_attack(u2) || type_can_fire(u2))
  320.         && uu_acp_to_create(u, u2) > 0) {
  321.         backup = u2;
  322.         if (flip_coin()) {
  323.             u3 = u2;
  324.             break;
  325.         }
  326.         }
  327.     }
  328.     }
  329.     if (u3 == NONUTYPE) u3 = backup;
  330.     if (is_unit_type(u3)) {
  331.     task = unit->plan->tasks;
  332.         if (task == NULL || task->type != TASK_BUILD) {
  333.         DMprintf("%s supporting offense by building %s\n",
  334.              unit_desig(unit), u_type_name(u3));
  335.         set_construction(unit, u3, 2);
  336.     } else {
  337.         DMprintf("%s already building, leaving alone\n",
  338.              unit_desig(unit));
  339.     }
  340.     } else {
  341.         DMprintf("%s has no way to support an offensive\n", unit_desig(unit));
  342.     }
  343. }
  344.  
  345. void
  346. set_construction(unit, u, num)
  347. Unit *unit;
  348. int u, num;
  349. {
  350.     Task *task = unit->plan->tasks;
  351.  
  352.     if (task != NULL && task->type == TASK_BUILD) {
  353.     task->args[0] = u;
  354.     task->args[1] = num;
  355.     task->args[2] = 0;
  356.     } else {
  357.     push_build_task(unit, u, num);
  358.     }
  359. }
  360.  
  361. /* Defensive units don't go out looking for trouble, but they should
  362.    react strongly to threats. */
  363.  
  364. void
  365. plan_defense(unit)
  366. Unit *unit;
  367. {
  368.     if (resupply_if_low(unit)) return;
  369.     if (rearm_if_low(unit)) return;
  370.     if (unit->plan->tasks) {
  371.         /* (should analyze and maybe decide to change task) */
  372.         execute_task(unit);
  373.         return;
  374.     }
  375.     if (0 /* has specific goal */) {
  376.     } else if (can_fire(unit)) {
  377.     /* No special goal, look for something to shoot at. */
  378.     if (fire_at_opportunity(unit)) {
  379.         execute_task(unit);
  380.         return;
  381.     }
  382.     } else if (can_attack(unit)) {
  383.     /* can move a short ways to attack an interloper */
  384.     }
  385.     /* (might be able to defend by interposing self?) */
  386.     if (!unit->plan->reserve) {
  387.     /* Just stay in reserve for now. */
  388.     DMprintf("%s going into defensive reserve\n", unit_desig(unit));
  389.     unit->plan->reserve = TRUE;
  390.     }
  391. }
  392.  
  393. void
  394. plan_exploration(unit)
  395. Unit *unit;
  396. {
  397.     Plan *plan = unit->plan;
  398.     int u = unit->type;
  399.     int x, y, w, h, range, x1, y1;
  400.     Side *us = unit->side;
  401.  
  402.     /* If the world has no secrets, exploration is sort of pointless. */
  403.     if (g_see_all()) {
  404.         plan->reserve = TRUE;
  405.         return;
  406.     }
  407.     if (resupply_if_low(unit))
  408.       return;
  409.     if (capture_indep_if_nearby(unit))
  410.       return;
  411.     if (capture_useful_if_nearby(unit))
  412.       return;
  413.     if (plan->tasks) {
  414.         /* (should see if a change of task is worthwhile) */
  415.         execute_task(unit);
  416.         return;
  417.     }
  418.     if (plan->maingoal) {
  419.     switch (plan->maingoal->type) {
  420.       case GOAL_VICINITY_KNOWN:
  421.       case GOAL_VICINITY_HELD:
  422.         if (mobile(u)) {
  423.         x = plan->maingoal->args[0];  y = plan->maingoal->args[1];
  424.         w = plan->maingoal->args[2];  h = plan->maingoal->args[3];
  425.         if (distance(x, y, unit->x, unit->y) > max(w, h)) {
  426.                 if (random_point_near(x, y, max(w, h) / 2, &x1, &y1)) {
  427.                 x = x1;  y = y1;
  428.                 }
  429.             DMprintf("%s to explore towards %d,%d\n",
  430.                  unit_desig(unit), x, y);
  431.             push_movenear_task(unit, x, y, max(w, h) / 2);
  432.         } else {
  433.             if (explore_reachable_cell(unit, max(w, h) + 2)) {
  434.             } else if (us != NULL && side_has_ai(us) && ai_guide_explorer(us, unit)) {
  435.             } else {
  436.                 if (flip_coin()) {
  437.                 DMprintf("%s clearing goal\n", unit_desig(unit));
  438.                 plan->maingoal = NULL;
  439.                 }
  440.             DMprintf("%s to walk randomly\n", unit_desig(unit));
  441.             random_walk(unit);
  442.             }
  443.         }
  444.         } else {
  445.         plan_explorer_support(unit);
  446.         }
  447.         break;
  448.       case GOAL_WORLD_KNOWN:
  449.         if (mobile(u)) {
  450.         if (explore_reachable_cell(unit, area.maxdim)) {
  451.         } else if (us != NULL && side_has_ai(us)
  452.                && ai_guide_explorer(us, unit)) {
  453.         } else {
  454.             DMprintf("%s to walk randomly\n", unit_desig(unit));
  455.             random_walk(unit);
  456.         }
  457.         } else {
  458.         plan_explorer_support(unit);
  459.         }
  460.         break;
  461.       default:
  462.         DMprintf("%s goal %s?\n",
  463.              unit_desig(unit), goal_desig(unit->plan->maingoal));
  464.         break;
  465.     }
  466.     } else {
  467.     /* No specific goal, just poke around. */
  468.     if (mobile(u)) {
  469.         range = area.maxdim / 2;
  470.         if (explore_reachable_cell(unit, range)) {
  471.         } else if (us != NULL && side_has_ai(us) && ai_guide_explorer(us, unit)) {
  472.         } else {
  473.             if (flip_coin()) {
  474.                 /* (should call a plan eraser) */
  475.                 unit->plan->type = PLAN_NONE;
  476.             }
  477.         DMprintf("%s to walk randomly\n", unit_desig(unit));
  478.         random_walk(unit);
  479.         }
  480.     } else {
  481.         plan_explorer_support(unit);
  482.     }
  483.     }
  484.     if (plan->tasks) {
  485.         execute_task(unit);
  486.     } else {
  487.         if (probability(10)) {
  488.             DMprintf("no tasks, going to sleep (dunno why)\n");
  489.             plan->asleep = TRUE;
  490.         }
  491.     }
  492. }
  493.  
  494. void
  495. plan_explorer_support(unit)
  496. Unit *unit;
  497. {
  498.     int u = unit->type, u2, u3, backup;
  499.     Task *task;
  500.  
  501.     if (side_has_ai(unit->side)) {
  502.     u3 = ai_preferred_build_type(unit->side, unit, PLAN_EXPLORATORY);
  503.     } else {
  504.     for_all_unit_types(u2) {
  505.         if (mobile(u2)
  506.         && 1 /* better on more kinds of terrain? */
  507.         && uu_acp_to_create(u, u2) > 0) {
  508.         backup = u2;
  509.         if (flip_coin()) {
  510.             u3 = u2;
  511.             break;
  512.         }
  513.         }
  514.     }
  515.     }
  516.     if (u3 == NONUTYPE) u3 = backup;
  517.     if (u3 != NONUTYPE) {
  518.     task = unit->plan->tasks;
  519.         if (task == NULL || task->type != TASK_BUILD) {
  520.         DMprintf("%s supporting exploration by building %s\n",
  521.              unit_desig(unit), u_type_name(u3));
  522.         push_build_task(unit, u3, 2);
  523.     } else {
  524.         DMprintf("%s already building, leaving alone\n",
  525.              unit_desig(unit));
  526.     }
  527.     } else {
  528.         DMprintf("%s has no way to support exploration\n", unit_desig(unit));
  529.     }
  530. }
  531.  
  532. int victimx, victimy, victimrating;
  533.  
  534. int
  535. victim_here(x, y)
  536. int x, y;
  537. {
  538.     int u2 = NONUTYPE, uview, rating, dist;
  539.     Unit *unit2;
  540.     Side *side = tmpunit->side, *oside = NULL;
  541.  
  542.     if (g_see_all()
  543.     || cover(side, x, y) > 0 /* should be "guaranteed to see" */) {
  544.     if ((unit2 = unit_at(x, y)) != NULL) {
  545.         u2 = unit2->type;
  546.         oside = unit2->side;
  547.     } else {
  548.         return FALSE;
  549.     }
  550.     } else if (terrain_view(side, x, y) != UNSEEN
  551.            && (uview = unit_view(side, x, y)) != EMPTY) {
  552.     u2 = vtype(uview);
  553.     oside = side_n(vside(uview));
  554.     } else {
  555.     return FALSE;
  556.     }
  557.     if (is_unit_type(u2)
  558.     && enemy_side(side, oside)
  559.     && ((could_hit(tmpunit->type, u2)
  560.         && uu_damage(tmpunit->type, u2) > 0
  561.         && (!worth_capturing(side, u2, oside, x, y)
  562.             || uu_capture(tmpunit->type, u2) > 0))
  563.         || uu_capture(tmpunit->type, u2) > 0)
  564.     ) {
  565.     rating = uu_zz_bhw(tmpunit->type, u2);
  566.     if (capture_chance(tmpunit->type, u2, oside) > 0) {
  567.         return TRUE;
  568.     }
  569.     if (tmpunit->occupant != NULL
  570.         && could_hit(u2, tmpunit->type)
  571.         && uu_damage(u2, tmpunit->type) > 0
  572.         /* and valuable occupants not protected... */
  573.         ) {
  574.         return FALSE;
  575.     }
  576.     /* Further-away units are less interesting than closer ones. */
  577.     dist = distance(tmpunit->x, tmpunit->y, x, y);
  578.     if (dist > u_acp(tmpunit->type)) {
  579.         rating /= max(1, isqrt(dist - u_acp(tmpunit->type)));
  580.     }
  581.     if (rating > victimrating || (rating == victimrating && flip_coin())) {
  582.         victimx = x;  victimy = y;
  583.         victimrating = rating;
  584.     }
  585.     }
  586.     return FALSE;
  587. }
  588.  
  589. /* This decides whether a given unit type seen at a given location is worth
  590.    trying to capture. */
  591.  
  592. int
  593. worth_capturing(side, u2, side2, x, y)
  594. Side *side, *side2;
  595. int u2, x, y;
  596. {
  597.     int u, bestchance = 0;
  598.  
  599.     /* See how likely we are to be able to capture the type. */
  600.     for_all_unit_types(u) {
  601.     bestchance = max(capture_chance(u, u2, side2), bestchance);
  602.     }
  603.     if (bestchance == 0)
  604.       return FALSE;
  605.     /* (should account for other considerations too, like which types of units we have) */
  606.     return TRUE;
  607. }
  608.  
  609. /* This routine looks for somebody, anybody to attack. */
  610.  
  611. int
  612. go_after_victim(unit, range)
  613. Unit *unit;
  614. int range;
  615. {
  616.     int x, y, rslt;
  617.  
  618.     tmpunit = unit;
  619.     DMprintf("%s seeking victim within %d; found ",
  620.          unit_desig(unit), range);
  621.     victimrating = -9999;
  622.     rslt = search_around(unit->x, unit->y, range, victim_here, &x, &y, 1);
  623.     if (rslt) {
  624.     DMprintf("one at %d,%d\n", x, y);
  625.     /* Set up a task to go after the unit found. */
  626.     /* (should be able to set capture task if better) */
  627.     set_hit_task(unit, x, y);
  628.     if (unit->transport != NULL
  629.         && mobile(unit->transport->type)
  630.         && unit->transport->plan) {
  631.         set_movenear_task(unit->transport, x, y, 1);
  632.     }
  633.     } else if (victimrating > -9999) {
  634.     DMprintf("one (rated %d) at %d,%d\n", victimrating, victimx, victimy);
  635.     /* Set up a task to go after the unit found. */
  636.     /* (should be able to set capture task if better) */
  637.     set_hit_task(unit, victimx, victimy);
  638.     if (unit->transport != NULL
  639.         && mobile(unit->transport->type)
  640.         && unit->transport->plan) {
  641.         set_movenear_task(unit->transport, victimx, victimy, 1);
  642.     }
  643.     } else {
  644.     DMprintf("nothing\n");
  645.     }
  646.     return rslt;
  647. }
  648.  
  649. int targetx, targety, targetrating;
  650.  
  651. int
  652. target_here(x, y)
  653. int x, y;
  654. {
  655.     int u2 = NONUTYPE, uview, rating, dist;
  656.     Unit *unit2;
  657.     Side *side = tmpunit->side, *oside = NULL;
  658.  
  659.     if (g_see_all()
  660.     || cover(side, x, y) > 0 /* should be "guaranteed to see" */) {
  661.     if ((unit2 = unit_at(x, y)) != NULL) {
  662.         u2 = unit2->type;
  663.         oside = unit2->side;
  664.     } else {
  665.         /* Nothing to shoot at here. */
  666.         return FALSE;
  667.     }
  668.     } else if (terrain_view(side, x, y) != UNSEEN
  669.            && (uview = unit_view(side, x, y)) != EMPTY) {
  670.     u2 = vtype(uview);
  671.     oside = side_n(vside(uview));
  672.     } else {
  673.     /* Nothing (or at least nothing visible) to shoot at here. */
  674.     return FALSE;
  675.     }
  676.     if (is_unit_type(u2)
  677.     && enemy_side(side, oside)
  678.     && could_hit(tmpunit->type, u2)
  679.     && uu_damage(tmpunit->type, u2) > 0
  680.     /* and have correct ammo */
  681.     ) {
  682.         rating = uu_hit(tmpunit->type, u2);
  683.     /* Further-away units are less interesting than closer ones. */
  684.     dist = distance(tmpunit->x, tmpunit->y, x, y);
  685.     /* (effect should be quality of fire) */
  686.     if (rating > targetrating || (rating == targetrating && flip_coin())) {
  687.         targetx = x;  targety = y;
  688.         targetrating = rating;
  689.     }
  690.     }
  691.     return FALSE;
  692. }
  693.  
  694. int
  695. fire_at_opportunity(unit)
  696. Unit *unit;
  697. {
  698.     int x, y, range, rslt;
  699.  
  700.     tmpunit = unit;
  701.     range = u_range(unit->type);
  702.     targetrating = -9999;
  703.     DMprintf("%s seeking target within %d; found ",
  704.              unit_desig(unit), range);
  705.     rslt = search_around(unit->x, unit->y, range, target_here, &x, &y, 1);
  706.     if (rslt) {
  707.     DMprintf("one at %d,%d\n", x, y);
  708.     /* Set up a task to shoot at the unit found. */
  709.     set_hit_task(unit, x, y);
  710.     } else if (targetrating > -9999) {
  711.     DMprintf("one (rated %d) at %d,%d\n", targetrating, x, y);
  712.     /* Set up a task to shoot at the unit found. */
  713.     set_hit_task(unit, targetx, targety);
  714.     } else {
  715.     DMprintf("nothing\n");
  716.     }
  717.     return rslt;
  718. }
  719.  
  720. /* Check to see if our grand plans are at risk of being sideswiped by lack of
  721.    supply, and set up a resupply task if so. */
  722.  
  723. int
  724. resupply_if_low(unit)
  725. Unit *unit;
  726. {
  727.     int u = unit->type, m, lowm = NONMTYPE;
  728.     Task *curtask = unit->plan->tasks;
  729.  
  730.     if (!mobile(u)) return FALSE;
  731.     for_all_material_types(m) {
  732.     if ((um_base_consumption(u, m) > 0 || um_consumption_per_move(u, m) > 0)
  733.         && 2 * unit->supply[m] < um_storage_x(u, m)) {
  734.         lowm = m;
  735.         break;
  736.     }
  737.     }
  738.     if (lowm != NONMTYPE) {
  739.     if (curtask != NULL
  740.         && curtask->type == TASK_MOVETO
  741.         && supplies_here(unit, curtask->args[0], curtask->args[1], lowm))
  742.       /* Let the movement task execute. */
  743.       return FALSE;
  744.     /* Otherwise set up a task. */
  745.     DMprintf("%s low on %s, looking for source\n",
  746.          unit_desig(unit), m_type_name(m));
  747.     set_resupply_task(unit);
  748.     return (execute_task(unit) != TASK_FAILED);
  749.     }
  750.     return FALSE;
  751. }
  752.  
  753. int
  754. rearm_if_low(unit)
  755. Unit *unit;
  756. {
  757.     int u = unit->type, m, lowm = NONMTYPE;
  758.     Task *curtask = unit->plan->tasks;
  759.  
  760.     if (!mobile(u)) return FALSE;
  761.     for_all_material_types(m) {
  762.     if (um_consumption_per_attack(u, m) > 0
  763.         && unit->supply[m] == 0
  764.         && um_storage_x(u, m) > 0) {
  765.         lowm = m;
  766.         break;
  767.     }
  768.     }
  769.     if (lowm != NONMTYPE) {
  770.     if (curtask != NULL
  771.         && curtask->type == TASK_MOVETO
  772.         && supplies_here(unit, curtask->args[0], curtask->args[1], lowm))
  773.       /* Let the movement task execute. */
  774.       return FALSE;
  775.     /* Otherwise set up a task. */
  776.     DMprintf("%s low on %s, looking for source\n",
  777.          unit_desig(unit), m_type_name(m));
  778.     set_resupply_task(unit);
  779.     return (execute_task(unit) != TASK_FAILED);
  780.     }
  781.     return FALSE;
  782. }
  783.  
  784. int
  785. supplies_here(unit, x, y, m)
  786. Unit *unit;
  787. int x, y, m;
  788. {
  789.     Unit *unit2;
  790.  
  791.     for_all_stack(x, y, unit2) {
  792.     if (unit_trusts_unit(unit2, unit)
  793.         && unit2->supply[m] > 0) {
  794.         return TRUE;
  795.     }
  796.     }
  797.     return FALSE;
  798. }
  799.  
  800. int
  801. indep_captureable_here(x, y)
  802. int x, y;
  803. {
  804.     int u2 = NONUTYPE, uview;
  805.     Unit *unit2;
  806.     Side *side = tmpunit->side, *side2 = NULL;
  807.  
  808.     if (g_see_all()
  809.     || cover(side, x, y) > 0 /* should be "guaranteed to see" */) {
  810.     if ((unit2 = unit_at(x, y)) != NULL) {
  811.         u2 = unit2->type;
  812.         side2 = unit2->side;
  813.     } else {
  814.         return FALSE;
  815.     }
  816.     } else if (terrain_view(side, x, y) != UNSEEN
  817.            && (uview = unit_view(side, x, y)) != EMPTY) {
  818.     u2 = vtype(uview);
  819.     side2 = side_n(vside(uview));
  820.     } else {
  821.     return FALSE;
  822.     }
  823.     return (is_unit_type(u2)
  824.             && side2 == NULL
  825.         && capture_chance(tmpunit->type, u2, side2) > 0);
  826. }
  827.  
  828. /*  */
  829.  
  830. int
  831. capture_indep_if_nearby(unit)
  832. Unit *unit;
  833. {
  834.     int u = unit->type, range = 5;
  835.     int x, y, rslt;
  836.  
  837.     if (!mobile(u)) return FALSE;
  838.     if (!could_capture_any(unit->type)) return FALSE;
  839.     tmpunit = unit;
  840.     DMprintf("%s searching for easy capture within %d; found ",
  841.          unit_desig(unit), range);
  842.     rslt = search_around(unit->x, unit->y, range, indep_captureable_here,
  843.              &x, &y, 1);
  844.     if (rslt) {
  845.     DMprintf("one at %d,%d\n", x, y);
  846.     /* Set up a task to go after the unit found. */
  847.     set_capture_task(unit, x, y);
  848.     if (unit->transport
  849.         && mobile(unit->transport->type)
  850.         && unit->transport->plan) {
  851.         push_movenear_task(unit->transport, x, y, 1);
  852.     }
  853.     return (execute_task(unit) != TASK_FAILED);
  854.     } else {
  855.     DMprintf("nothing\n");
  856.     }
  857.     return FALSE;
  858. }
  859.  
  860. int
  861. useful_captureable_here(x, y)
  862. int x, y;
  863. {
  864.     int u2 = NONUTYPE, uview;
  865.     Unit *unit2;
  866.     Side *side = tmpunit->side, *oside = NULL;
  867.  
  868.     if (g_see_all()
  869.     || cover(side, x, y) > 0 /* should be "guaranteed to see" */) {
  870.     for_all_stack(x, y, unit2) {
  871.         u2 = unit2->type;
  872.         oside = unit2->side;
  873.             if (is_unit_type(u2)
  874.             && !trusted_side(side, oside)
  875.         && capture_chance(tmpunit->type, u2, oside) > 0
  876.         && useful_type(side, u2)
  877.         ) return TRUE;
  878.     }
  879.     } else if (terrain_view(side, x, y) != UNSEEN
  880.            && (uview = unit_view(side, x, y)) != EMPTY) {
  881.     u2 = vtype(uview);
  882.     oside = side_n(vside(uview));
  883.         return (is_unit_type(u2)
  884.             && !trusted_side(side, oside)
  885.         && capture_chance(tmpunit->type, u2, oside) > 0
  886.         && useful_type(side, u2)
  887.         );
  888.     } else {
  889.     }
  890.     return FALSE;
  891. }
  892.  
  893. /* Return true if the given type of unit is useful in some way to the
  894.    given side.  This is almost always true. */
  895.  
  896. int
  897. useful_type(side, u)
  898. Side *side;
  899. int u;
  900. {
  901.     /* (should be false for types we can't own, can't operate, etc) */
  902.     return TRUE;
  903. }
  904.  
  905. /*  */
  906.  
  907. int
  908. capture_useful_if_nearby(unit)
  909. Unit *unit;
  910. {
  911.     int u = unit->type, range = 2;
  912.     int x, y, rslt;
  913.  
  914.     if (!mobile(u)) return FALSE;
  915.     if (!could_capture_any(unit->type)) return FALSE;
  916.     tmpunit = unit;
  917.     DMprintf("%s searching for useful capture within %d; found ",
  918.          unit_desig(unit), range);
  919.     rslt = search_around(unit->x, unit->y, range, useful_captureable_here,
  920.              &x, &y, 1);
  921.     if (rslt) {
  922.     DMprintf("one at %d,%d\n", x, y);
  923.     /* Set up a task to go after the unit found. */
  924.     set_capture_task(unit, x, y);
  925.     if (unit->transport
  926.         && mobile(unit->transport->type)
  927.         && unit->transport->plan) {
  928.         push_movenear_task(unit->transport, x, y, 1);
  929.     }
  930.     return (execute_task(unit) != TASK_FAILED);
  931.     } else {
  932.     DMprintf("nothing\n");
  933.     }
  934.     return FALSE;
  935. }
  936.  
  937. int
  938. could_capture_any(u)
  939. int u;
  940. {
  941.     int u2;
  942.  
  943.     for_all_unit_types(u2) {
  944.     if (uu_capture(u, u2) > 0 || uu_indep_capture(u, u2) > 0) return TRUE;
  945.     /* also check if u2 in game, on other side, etc? */
  946.     }
  947.     return FALSE;
  948. }
  949.  
  950. /* This is a semi-testing routine that basically picks something for the
  951.    unit to do without worrying about its validity.  The rest of the
  952.    system should function correctly no matter what this thing comes up with.
  953.    Piles of warnings are likely, but that's OK. */
  954.  
  955. void
  956. plan_random(unit)
  957. Unit *unit;
  958. {
  959.     int dir, x1, y1;
  960.     TaskType tasktype;
  961.     Action action;
  962.     char *argtypestr;
  963.  
  964.     if (flip_coin()) {
  965.     if (unit->plan->tasks) {
  966.         execute_task(unit);
  967.         return;
  968.     }
  969.     /* Pick a random task. */
  970.     tasktype = xrandom((int) NUMTASKTYPES);
  971.     switch (tasktype) {
  972.       case TASK_NONE:
  973.         unit->plan->tasks = create_task (tasktype);
  974.         break;
  975.       case TASK_BUILD:
  976.         unit->plan->tasks = create_task (tasktype);
  977.         break;
  978.       case TASK_RESEARCH:
  979.         unit->plan->tasks = create_task (tasktype);
  980.         break;
  981.       case TASK_CAPTURE_UNIT:
  982.         dir = random_dir();
  983.         point_in_dir(unit->x, unit->y, dir, &x1, &y1);
  984.         set_capture_task(unit, x1, y1);
  985.         break;
  986.       case TASK_DO_ACTION:
  987.         unit->plan->tasks = create_task (tasktype);
  988.         break;
  989.       case TASK_HIT_POSITION:
  990.         unit->plan->tasks = create_task (tasktype);
  991.         break;
  992.       case TASK_HIT_UNIT:
  993.         unit->plan->tasks = create_task (tasktype);
  994.         break;
  995.       case TASK_MOVEDIR:
  996.         unit->plan->tasks = create_task (tasktype);
  997.         break;
  998.       case TASK_MOVETO:
  999.         dir = random_dir();
  1000.         point_in_dir(unit->x, unit->y, dir, &x1, &y1);
  1001.         order_moveto(unit, x1, y1);
  1002.         break;
  1003.       case TASK_OCCUPY:
  1004.         unit->plan->tasks = create_task (tasktype);
  1005.         break;
  1006.       case TASK_PICKUP:
  1007.         unit->plan->tasks = create_task (tasktype);
  1008.         break;
  1009.       case TASK_REPAIR:
  1010.         unit->plan->tasks = create_task (tasktype);
  1011.         break;
  1012.       case TASK_RESUPPLY:
  1013.         set_resupply_task(unit);
  1014.         break;
  1015.       case TASK_SENTRY:
  1016.         unit->plan->tasks = create_task (tasktype);
  1017.         break;
  1018.       default:
  1019.         case_panic("task type", tasktype);
  1020.         break;
  1021.     }
  1022.     }
  1023.     if (unit->plan && unit->plan->tasks)
  1024.       return;
  1025.     /* Otherwise go for a random action. */
  1026.     memset(&action, 0, sizeof(Action));
  1027.     action.type = (ActionType) xrandom((int) NUMACTIONTYPES);
  1028.     argtypestr = actiondefns[(int) action.type].argtypes;
  1029.     make_plausible_random_args(argtypestr, 0, &(action.args[0]), unit);
  1030.     if (flip_coin()) {
  1031.     action.actee = unit->id;
  1032.     } else {
  1033.     while (find_unit(action.actee = xrandom(numunits)+1) == NULL
  1034.            && probability(98));
  1035.     }
  1036.     unit->act->nextaction = action;
  1037.     DMprintf("%s will randomly try %s\n",
  1038.          unit_desig(unit), action_desig(&action));
  1039. }
  1040.  
  1041. /* This attempts to make some vaguely plausible arguments for an action,
  1042.    using the types of each arg as a guide.  It also generates *invalid*
  1043.    arguments occasionally, which tests error checking in the actions' code. */
  1044.  
  1045. void
  1046. make_plausible_random_args(argtypestr, i, args, unit)
  1047. char *argtypestr;
  1048. int i;
  1049. short *args;
  1050. Unit *unit;
  1051. {
  1052.     char argch;
  1053.     int    slen;
  1054.     long arg;
  1055.  
  1056.     slen = strlen(argtypestr);
  1057.     while (i < slen && i < 10) {
  1058.     argch = argtypestr[i];
  1059.     switch (argch) {
  1060.       case 'n':
  1061.         arg = (flip_coin() ? xrandom(10) :
  1062.            (flip_coin() ? xrandom(100) :
  1063.             (xrandom(20000) - 10000)));
  1064.         break;
  1065.       case 'u':
  1066.         /* Go a little outside range, so as to get some invalid types. */
  1067.         arg = xrandom(numutypes + 2) - 1;
  1068.         break;
  1069.       case 'm':
  1070.         arg = xrandom(nummtypes + 2) - 1;
  1071.         break;
  1072.       case 't':
  1073.         arg = xrandom(numttypes + 2) - 1;
  1074.         break;
  1075.       case 'x':
  1076.         arg = (unit != NULL && flip_coin() ? (unit->x + xrandom(5) - 2) :
  1077.            (xrandom(area.width + 4) - 2));
  1078.         break;
  1079.       case 'y':
  1080.         arg = (unit != NULL && flip_coin() ? (unit->y + xrandom(5) - 2) :
  1081.            (xrandom(area.height + 4) - 2));
  1082.         break;
  1083.       case 'z':
  1084.         arg = (flip_coin() ? 0 : xrandom(10));
  1085.         break;
  1086.       case 'd':
  1087.         arg = random_dir();
  1088.         break;
  1089.       case 'U':
  1090.         /* Cast around for a valid unit. */
  1091.         while (find_unit(arg = xrandom(numunits)+1) == NULL
  1092.            && probability(98));
  1093.         break;
  1094.       case 'S':
  1095.         arg = xrandom(numsides + 3) - 1;
  1096.         break;
  1097.       default:
  1098.         run_warning("Garbled action arg type '%c'\n", argch);
  1099.         arg = 0;
  1100.         break;
  1101.     }
  1102.     args[i++] = arg;
  1103.     }
  1104. }
  1105.  
  1106. /* This routine calculates a basic plan for the given unit. */
  1107.  
  1108. void
  1109. decide_plan(side, unit)
  1110. Side *side;
  1111. Unit *unit;
  1112. {
  1113.     /* (should be able to make plan object if missing) */
  1114.     if (side == NULL)
  1115.       return;
  1116.     DMprintf("%s deciding its plan", unit_desig(unit));
  1117.     if (side_has_ai(side)) {
  1118.         DMprintf(", using %s AI", side_desig(side));
  1119.         ai_decide_plan(side, unit);
  1120.         DMprintf(" - plan is now %s", plan_desig(unit->plan));
  1121.     }
  1122.     /* If the AI didn't decide anything, or if this is a human-run
  1123.        unit, then just say the unit will be following orders. */
  1124.     /* (doctrine should be able to ask for assortment of plans.) */
  1125.     if (unit->plan->type == PLAN_NONE) {
  1126.     if (side_has_display(side))  {
  1127.         DMprintf(", but will just be following orders");
  1128.         unit->plan->type = PLAN_PASSIVE;
  1129.         clear_task_agenda(unit->plan);
  1130.         /* Special-case cities in the intro game to automatically
  1131.            start producing infantry initially. */
  1132.         if (g_turn() <= 1
  1133.         && mainmodule != NULL
  1134.         && mainmodule->name != NULL
  1135.         && strcmp(mainmodule->name, "intro") == 0
  1136.         && strcmp(u_type_name(unit->type), "city") == 0) {
  1137.         push_build_task(unit, 0, 99);
  1138.         }
  1139.     } else {
  1140.         /* or PLAN_NONE? */
  1141.         unit->plan->type = PLAN_PASSIVE;
  1142.         clear_task_agenda(unit->plan);
  1143.         unit->plan->asleep = TRUE;
  1144.     }
  1145.     }
  1146.     DMprintf("\n");
  1147. }
  1148.  
  1149. int
  1150. doctrine_allows_wait(unit)
  1151. Unit *unit;
  1152. {
  1153.     int everask = units_doctrine(unit, everaskside);
  1154.  
  1155.     return (everask);
  1156. }
  1157.  
  1158. /* Record the unit as waiting for orders about what to do. */
  1159.  
  1160. void
  1161. wait_for_orders(unit)
  1162. Unit *unit;
  1163. {
  1164.     if (!unit->plan->waitingfortasks) {
  1165.     ++(unit->side->numwaiting);
  1166.     }
  1167.     unit->plan->waitingfortasks = TRUE;
  1168. }
  1169.  
  1170. /* This runs if an order-following unit has been told to just pick something
  1171.    random to do. */
  1172.  
  1173. void
  1174. decide_tasks(unit)
  1175. Unit *unit;
  1176. {
  1177.     random_walk(unit);
  1178. }
  1179.  
  1180. /* Random walking just attempts to move around. */
  1181.  
  1182. void
  1183. random_walk(unit)
  1184. Unit *unit;
  1185. {
  1186.     int dir = random_dir(), x1, y1, tries = 0;
  1187.  
  1188.     while (!interior_point_in_dir(unit->x, unit->y, dir, &x1, &y1)) {
  1189.         if (++tries > 500) {  run_warning("something is wrong");  break;  }
  1190.         dir = random_dir();
  1191.     }
  1192.     set_moveto_task(unit, x1, y1);
  1193. }
  1194.  
  1195. /* Put a unit in reserve. */
  1196.  
  1197. void
  1198. reserve_unit(side, unit)
  1199. Side *side;
  1200. Unit *unit;
  1201. {
  1202.     if (unit->plan) {
  1203.     unit->plan->reserve = TRUE;
  1204.     update_unit_display(side, unit, TRUE);
  1205.     }
  1206. }
  1207.  
  1208. /* General routine to wake a unit up (and maybe all its cargo). */
  1209.  
  1210. void
  1211. wake_unit(unit, wakeocc, reason, unit2)
  1212. Unit *unit, *unit2;
  1213. int wakeocc, reason;
  1214. {
  1215.     Unit *occ;
  1216.  
  1217.     if (unit->plan) {
  1218.     unit->plan->asleep = unit->plan->reserve = FALSE;
  1219.     /* (echo to interface?) */
  1220.     }
  1221.     if (wakeocc) {
  1222.     for_all_occupants(unit, occ) wake_unit(occ, wakeocc, reason, unit2);
  1223.     }
  1224.     /* (should do something with other args) */
  1225. }
  1226.  
  1227. /* The area wakeup. */
  1228.  
  1229. static int tmpflag;
  1230.  
  1231. static void
  1232. wake_at(x, y)
  1233. int x, y;
  1234. {
  1235.     Unit *unit;
  1236.  
  1237.     for_all_stack(x, y, unit) {
  1238.     if (side_controls_unit(tmpside, unit)) {
  1239.         wake_unit(unit, tmpflag, 0, NULL);
  1240.     }
  1241.     }
  1242. }
  1243.  
  1244. void
  1245. wake_area(side, x, y, n, occs)
  1246. Side *side;
  1247. int x, y, n, occs;
  1248. {
  1249.     tmpside = side;
  1250.     tmpflag = occs;
  1251.     apply_to_area(x, y, n, wake_at);
  1252. }
  1253.  
  1254. void
  1255. set_formation(unit, leader, x, y, dist, flex)
  1256. Unit *unit, *leader;
  1257. int x, y, dist, flex;
  1258. {
  1259.     Plan *plan = unit->plan;
  1260.     Goal *goal;
  1261.  
  1262.     if (plan == NULL)
  1263.       return;
  1264.     if (!in_play(unit))
  1265.       return;
  1266.     if (leader != NULL) {
  1267.     if (!in_play(leader))
  1268.       return;
  1269.     goal = create_goal(GOAL_KEEP_FORMATION, unit->side, TRUE);
  1270.     goal->args[0] = leader->id;
  1271.     } else {
  1272.     if (!inside_area(x, y)) return;
  1273.     goal = create_goal(GOAL_KEEP_FORMATION, unit->side, TRUE);
  1274.     goal->args[0] = 0;
  1275.     }
  1276.     goal->args[1] = x;  goal->args[2] = y;
  1277.     goal->args[3] = dist;
  1278.     goal->args[4] = flex;
  1279.     plan->formation = goal;
  1280.     plan->funit = leader;
  1281. }
  1282.  
  1283. void
  1284. delay_unit(unit, flag)
  1285. Unit *unit;
  1286. int flag;
  1287. {
  1288.     if (in_play(unit) && unit->plan) {
  1289.     unit->plan->delayed = TRUE;
  1290.     }
  1291. }
  1292.  
  1293. /* Search for a base to move to.  "Extra" is our optimism level, i.e.
  1294.    extra distance we might be willing to consider. */
  1295.  
  1296. int
  1297. find_base(unit, pred, extra)
  1298. Unit *unit;
  1299. int (*pred)();
  1300. int extra;
  1301. {
  1302. #if 0
  1303.     int range;
  1304.     int ox, oy, ux = unit->x, uy = unit->y;
  1305.     
  1306.     route_max_distance = range = range_left(unit) + extra;
  1307.     route_max_distance = min(area.maxdim, range);
  1308.     if ((range * range < mside->numunits) ? 
  1309.     (search_around(ux, uy, range, pred, &ox, &oy, 1))  :
  1310.     (find_closest_unit(ux, uy, range, pred, &ox, &oy))) {
  1311.     order_moveto(unit, ox, oy);
  1312. /*    if (munit->plan->move_tries < 3)
  1313.       unit->plan->orders.flags |= SHORTESTPATH;
  1314.     unit->plan->orders.flags &=
  1315.       ~(ENEMYWAKE|NEUTRALWAKE|SUPPLYWAKE|ATTACKUNIT);
  1316. */
  1317.     DMprintf("(found base at %d,%d)", ox, oy);
  1318.     return TRUE;
  1319.     }
  1320. #endif
  1321.     return FALSE;
  1322. }
  1323.  
  1324. #if 0
  1325. /* See if we're in a bad way, either on supply or hits, and get to safety
  1326.    if possible.  */
  1327.  
  1328. int
  1329. maybe_return_home(unit)
  1330. Unit *unit;
  1331. {
  1332.     int u = unit->type;
  1333.     
  1334.     DMprintf("%s checking return (low %d moves %d); ",
  1335.          unit_desig(unit),
  1336.          low_supplies(unit), moves_till_low_supplies(unit));
  1337.     if (0 /* (low_supplies(unit)
  1338.      || munit->plan->move_tries > 6
  1339.      || (moves_till_low_supplies(unit) < min(3, unit->mp) &&
  1340.          unit->plan->wakeup_reason != WAKEENEMY))
  1341.     && !can_capture_neighbor(unit)
  1342.     && probability(100) */) {
  1343.     DMprintf("low supply, ");
  1344.     if (building(unit) && survival_time(unit) > 1 /* unit->schedule */) {
  1345.         DMprintf("decided to sit and produce\n");
  1346.         order_sentry(unit, 1);
  1347.         return TRUE;
  1348.     }
  1349.     if (find_base(unit, good_haven_p, 0)) {
  1350.         DMprintf("found a good base\n");
  1351.         return TRUE;
  1352.     } else if (find_base(unit, haven_p, 0)) {
  1353.         DMprintf("found a base\n");
  1354.         return TRUE;
  1355.     } else if (unit->transport != NULL) {
  1356.         DMprintf("in a transport, will sit\n");
  1357.         order_sentry(unit, 1);
  1358.     } else if (survive_to_build_base(unit) && unit->transport == NULL) {
  1359.         DMprintf("going to build a base\n");
  1360.         push_build_task(unit, machine_product(unit));
  1361.         order_sentry(unit, 1 /* unit->schedule */+1);
  1362.         return TRUE;
  1363.     } else if (find_base(unit, haven_p, 1)) {
  1364.         DMprintf("found a base\n");
  1365.         return TRUE;
  1366.     } else {
  1367.         DMprintf("but can't do anything about it\n");
  1368.     }
  1369.     }
  1370.     if ((cripple(unit) && probability(98))
  1371.     || probability(100 - ((100 * unit->hp) / u_hp(u)))) {
  1372.     /* note that crippled units cannot repair themselves */
  1373.     DMprintf("badly damaged, ");
  1374.     if (unit->transport && could_repair(u, unit->transport->type)) {
  1375.         DMprintf("%s will repair\n", unit_desig(unit->transport));
  1376.         order_sentry(unit, 1);
  1377.         return TRUE;
  1378.     } else {
  1379.         if (find_base(unit, shop_p, 0)) {
  1380.         DMprintf("found a base\n");
  1381.         return TRUE;
  1382.         } else {
  1383.         DMprintf("but no place to repair\n");
  1384.         }
  1385.     }
  1386.     }
  1387.     if (out_of_ammo(unit) >= 0 && probability(80)) {
  1388.     DMprintf("should reload, ");
  1389.     if (find_base(unit, haven_p, 0)) {
  1390.         DMprintf("found a base\n");
  1391.         return TRUE;
  1392.     } else {
  1393.         if (/* hack */ 0 && survive_to_build_base(unit) && 
  1394.         unit->transport == NULL && probability(90)) {
  1395.         DMprintf("going to build something\n");
  1396.         push_build_task(unit, machine_product(unit));
  1397.         order_sentry(unit, 1 /* unit->schedule */+1);
  1398.         } else {
  1399.         DMprintf("but can't\n");
  1400.         }
  1401.     }
  1402.     }
  1403.     DMprintf("no need to return\n");
  1404.     return FALSE;
  1405. }
  1406. #endif
  1407.  
  1408. /* Return the distance that we can go by shortest path before running out */
  1409. /* of important supplies.  Will return at least 1, since we can *always* */
  1410. /* move one cell to safety.  This is a worst-case routine, too complicated */
  1411. /* to worry about units getting refreshed by terrain or whatever. */
  1412.  
  1413. int
  1414. range_left(unit)
  1415. Unit *unit;
  1416. {
  1417.     int u = unit->type, m, least = 12345; /* bigger than any real value */
  1418.     
  1419.     for_all_material_types(m) {
  1420.     if (um_consumption_per_move(u, m) > 0) {
  1421.         least = min(least, unit->supply[m] / um_consumption_per_move(u, m));
  1422.     }
  1423. #if 0
  1424.     if (um_base_consumption(u, m) > 0) {
  1425.         tmp = (u_speed(u) * unit->supply[m]) / um_base_consumption(u, m);
  1426.         least = min(least, tmp);
  1427.     }
  1428. #endif
  1429.     }
  1430.     return (least == 12345 ? 1 : least);
  1431. }
  1432.  
  1433. /* Estimate the goodness and badness of cells in the immediate vicinity. */
  1434.  
  1435. int
  1436. find_worths(range)
  1437. int range;
  1438. {
  1439.     return 0;
  1440. }
  1441.  
  1442. /* This is a heuristic estimation of the value of one unit type hitting */
  1443. /* on another.  Should take cost of production into account as well as the */
  1444. /* chance and significance of any effect. */
  1445.  
  1446. int
  1447. attack_worth(unit, e)
  1448. Unit *unit;
  1449. int e;
  1450. {
  1451.     int u = unit->type, worth;
  1452.  
  1453.     worth = uu_zz_bhw(u, e);
  1454.     /* Risk of death? */
  1455. /*    if (uu_damage(e, u) >= unit->hp)
  1456.     worth /= (could_capture(u, e) ? 1 : 4);
  1457.     if (could_capture(u, e)) worth *= 4; */
  1458.     return worth;
  1459. }
  1460.  
  1461. /* Support functions. */
  1462.  
  1463. /* Return true if the given position is threatened by the given unit type. */
  1464.  
  1465. int
  1466. threat(side, u, x0, y0)
  1467. Side *side;
  1468. int u, x0, y0;
  1469. {
  1470.     int d, x, y, thr = 0;
  1471.     Side *side2;
  1472.     int view;
  1473.  
  1474.     for_all_directions(d) {
  1475.         point_in_dir(x0, y0, d, &x, &y);
  1476.     view = 0 /* side_view(side, x, y) */;
  1477.     if (view != UNSEEN && view != EMPTY) {
  1478.         side2 = side_n(vside(view));
  1479.         if (allied_side(side, side2)) {
  1480.         if (uu_capture(u, vtype(view)) > 0) thr += 1000;
  1481.         if (uu_zz_bhw(u, vtype(view)) > 0) thr += 100;
  1482.         }
  1483.     }
  1484.     }
  1485.     return thr;
  1486. }
  1487.  
  1488. #if 0
  1489. /* Heuristics for units to build "bases". */
  1490.  
  1491. int
  1492. should_build_base(unit)
  1493. Unit *unit;
  1494. {
  1495.     DMprintf(
  1496.         "%s should build base survive %d base near %d wakeup %d - ",
  1497.                unit_desig(unit),
  1498.                survive_to_build_base(unit), base_nearby(unit,1),
  1499.                unit->plan->wakeup_reason);
  1500.     if ((exact_survive_to_build_base(unit)) && 0 &&
  1501.     unit->transport == NULL &&
  1502.     !any_base_nearby(unit,1) &&
  1503.     probability(90) &&
  1504.     unit->plan->wakeup_reason != WAKEENEMY) {
  1505.     push_build_task(unit, machine_product(unit));
  1506.     order_sentry(unit, 1 /* unit->schedule */+1);
  1507.     DMprintf("going to build a %d\n", unit->product);
  1508.     return TRUE;
  1509.     }
  1510.     if ((survive_to_build_base(unit) && 0 &&  probability(20)) &&
  1511.     unit->transport == NULL &&
  1512.     !any_base_nearby(unit,1) &&
  1513.     probability(90) &&
  1514.     !neutral_base_nearby(unit, 5) &&
  1515.     unit->plan->wakeup_reason != WAKEENEMY) {
  1516.     push_build_task(unit, machine_product(unit));
  1517.     order_sentry(unit, 1 /* unit->schedule */+1);
  1518.     DMprintf("going to build a %d\n", unit->product);
  1519.     return TRUE;
  1520.     }
  1521.     DMprintf("decided not to.\n");
  1522.     return FALSE;
  1523. }
  1524. #endif
  1525.  
  1526. #define UNITPRODUCT 0
  1527.  
  1528. void
  1529. pop_task(plan)
  1530. Plan *plan;
  1531. {
  1532.     Task *oldtask;
  1533.  
  1534.     if (plan->tasks) {
  1535.     oldtask = plan->tasks;
  1536.     plan->tasks = plan->tasks->next;
  1537.     free_task(oldtask);
  1538.     }
  1539. }
  1540.  
  1541. int
  1542. react_to_enemies(unit)
  1543. Unit *unit;
  1544. {
  1545.     return (unit->plan ? TRUE : FALSE);
  1546. }
  1547.  
  1548. /* Patrol just does move_to, but cycling waypoints around when the first */
  1549. /* one has been reached. */
  1550.  
  1551. int
  1552. move_patrol(unit)
  1553. Unit *unit;
  1554. {
  1555. #if 0
  1556.     int tx, ty;
  1557.  
  1558.     if (unit->plan->orders.rept-- > 0) {
  1559.     if (unit->x == unit->plan->orders.p.pt[0].x &&
  1560.         unit->y == unit->plan->orders.p.pt[0].y) {
  1561.         tx = unit->plan->orders.p.pt[0].x;
  1562.         ty = unit->plan->orders.p.pt[0].y;
  1563.         unit->plan->orders.p.pt[0].x = unit->plan->orders.p.pt[1].x;
  1564.         unit->plan->orders.p.pt[0].y = unit->plan->orders.p.pt[1].y;
  1565.         unit->plan->orders.p.pt[1].x = tx;
  1566.         unit->plan->orders.p.pt[1].y = ty;
  1567.     }
  1568.     return move_to(unit, unit->plan->orders.p.pt[0].x, unit->plan->orders.p.pt[0].y,
  1569.                (unit->plan->orders.flags & SHORTESTPATH));
  1570.     }
  1571. #endif
  1572.     return TRUE;
  1573. }
  1574.  
  1575. /* Basic routine to compute how long a unit will take to build something. */
  1576.  
  1577. int
  1578. build_time(unit, prod)
  1579. Unit *unit;
  1580. int prod;
  1581. {
  1582.     int schedule = 1 /* uu_make(unit->type, prod) */;
  1583.     int u, research_delay;
  1584.  
  1585.     /* Add penalty (or unpenalty!) for first unit of a type. */
  1586.     /* is "counts" a reliable way to test? */
  1587.     if (unit->side->counts[prod] <= 1) {
  1588. /*    research_delay = ((schedule * u_research(prod)) / 100);  */
  1589.     for_all_unit_types(u) {
  1590.         if (unit->side->counts[u] > 1) {
  1591.         research_delay -=
  1592.           (1 /*uu_make(unit->type, u)*/ * 
  1593.            uu_tech_crossover(prod, u)) / 100;
  1594.         }
  1595.         if (research_delay > 0) {
  1596.         schedule += research_delay;
  1597.         }
  1598.     }
  1599.     }
  1600.     return schedule;
  1601. }
  1602.  
  1603. void
  1604. clear_task_agenda(plan)
  1605. Plan *plan;
  1606. {
  1607.     int numcleared = 0;
  1608.     Task *oldtask;
  1609.  
  1610.     if (plan == NULL || plan->tasks == NULL)
  1611.       return;
  1612.     while (plan->tasks != NULL) {
  1613.         oldtask = plan->tasks;
  1614.         plan->tasks = plan->tasks->next;
  1615.         free_task(oldtask);
  1616.         ++numcleared;
  1617.     }
  1618.     if (numcleared > 0)
  1619.       Dprintf("Cleared %d tasks from %s\n", numcleared, plan_desig(plan));
  1620. }
  1621.  
  1622. Plan *
  1623. create_plan()
  1624. {
  1625.     Plan *plan = (Plan *) xmalloc(sizeof(Plan));
  1626.     return plan;
  1627. }
  1628.  
  1629. void 
  1630. free_plan(plan)
  1631. Plan *plan;
  1632. {
  1633.     if (plan == NULL)
  1634.       run_error("no plan here?");
  1635.     /* Make tasks available for reallocation. */
  1636.     clear_task_agenda(plan);
  1637.     free(plan);
  1638. }
  1639.  
  1640. /* Describe a plan succinctly. */
  1641.  
  1642. char *planbuf = NULL;
  1643.  
  1644. char *
  1645. plan_desig(plan)
  1646. Plan *plan;
  1647. {
  1648.     Task *task;
  1649.     int extra = 0;
  1650.  
  1651.     if (planbuf == NULL) planbuf = xmalloc(1000);
  1652.     if (plan == NULL) {
  1653.     sprintf(planbuf, "no plan");
  1654.     } else if (plan->type == PLAN_NONE) {
  1655.     sprintf(planbuf, "unformed plan");
  1656.     } else {
  1657.     if (plan->tasks) {
  1658.         tmpbuf[0] = '\0';
  1659.         for (task = plan->tasks; task != NULL; task = task->next) {
  1660.         if (strlen(tmpbuf) < 100) {
  1661.             strcat(tmpbuf, " ");
  1662.             strcat(tmpbuf, task_desig(task));
  1663.         } else {
  1664.             ++extra;
  1665.         }
  1666.         }
  1667.         if (extra > 0) {
  1668.         tprintf(tmpbuf, " ... %d more ...", extra);
  1669.         }
  1670.     } else {
  1671.         sprintf(tmpbuf, "no tasks");
  1672.     }
  1673.     sprintf(planbuf, "type %s %s",
  1674.         plantypenames[plan->type], goal_desig(plan->maingoal));
  1675.     if (plan->asleep)
  1676.       strcat(planbuf, " [asleep]");
  1677.     if (plan->reserve)
  1678.       strcat(planbuf, " [reserve]");
  1679.     if (plan->delayed)
  1680.       strcat(planbuf, " [delayed]");
  1681.     if (plan->waitingfortasks)
  1682.       strcat(planbuf, " [waiting for tasks]");
  1683.     if (plan->supply_alarm)
  1684.       strcat(planbuf, " [supply alarm]");
  1685.     if (plan->supply_is_low)
  1686.       strcat(planbuf, " [supply is low]");
  1687.     strcat(planbuf, tmpbuf);
  1688.     }
  1689.     return planbuf;
  1690. }
  1691.  
  1692. /* True if unit is in immediate danger of being captured. */
  1693. /* Needs check on capturer transport being seen. */
  1694.  
  1695. int
  1696. might_be_captured(unit)
  1697. Unit *unit;
  1698. {
  1699.     int d, x, y;
  1700.     Unit *unit2;
  1701.  
  1702.     for_all_directions(d) {
  1703.       if (interior_point_in_dir(unit->x, unit->y, d, &x, &y)) {
  1704.     if (((unit2 = unit_at(x, y)) != NULL) &&
  1705.         (enemy_side(unit->side, unit2->side)) &&
  1706.         (uu_capture(unit2->type, unit->type) > 0)) return TRUE;
  1707.       }
  1708.     }
  1709.     return FALSE;
  1710. }
  1711.  
  1712. void
  1713. force_global_replan(side)
  1714. Side *side;
  1715. {
  1716.     Unit *unit;
  1717.     
  1718.     for_all_side_units(side, unit) {
  1719.     if (in_play(unit) && unit->plan != NULL) {
  1720.         unit->plan->type = PLAN_NONE;
  1721.         clear_task_agenda(unit->plan);
  1722.         unit->plan->asleep = FALSE;
  1723.         unit->plan->reserve = FALSE;
  1724.         unit->plan->delayed = FALSE;
  1725.     }
  1726.     }
  1727. }
  1728.  
  1729. /* Auxiliary functions for unit planning in Xconq. */
  1730.  
  1731. /* router flags */
  1732.  
  1733. #define SAMEPATH 1
  1734. #define EXPLORE_PATH 2
  1735.  
  1736. /* These macros are a cache used for planning purposes by machines. */
  1737.  
  1738. #define markloc(x, y) (set_tmp1_at(x, y, mark))
  1739.  
  1740. #define markedloc(x, y) (tmp1_at(x, y) == mark)
  1741.  
  1742. #define get_fromdir(x, y) (tmp2_at(x, y))
  1743.  
  1744. #define set_fromdir(x, y, dir) (set_tmp2_at(x, y, dir))
  1745.  
  1746. #define get_dist(x, y) (tmp3_at(x, y))
  1747.  
  1748. #define set_dist(x, y, d) (set_tmp3_at(x, y, d))
  1749.  
  1750. int route_max_distance;
  1751.  
  1752. #if 0
  1753. /* Can this unit build a base without dying. */
  1754.  
  1755. int
  1756. survive_to_build_base(unit)
  1757. Unit *unit;
  1758. {
  1759.   return (base_builder(unit) &&
  1760.       survival_time(unit) > build_time(unit, base_builder(unit)));
  1761. }
  1762. #endif
  1763.  
  1764. #if 0
  1765. /* Is this the last chance for a unit to build a base without dying. */
  1766.  
  1767. int
  1768. exact_survive_to_build_base(unit)
  1769. Unit *unit;
  1770. {
  1771.   return (base_builder(unit) &&
  1772.       survival_time(unit) == (1 + build_time(unit, base_builder(unit))));
  1773. }
  1774. #endif
  1775.  
  1776. #if 0
  1777. /* Is there a machine base here. */
  1778.  
  1779. int
  1780. base_here(x, y)
  1781. int x, y;
  1782. {
  1783.     Unit *unit = unit_at(x, y);
  1784.  
  1785.     return (0 /* unit != NULL && unit->side == mside && isbase(unit) */) ;
  1786. }
  1787. #endif
  1788.  
  1789. #if 0
  1790. /* Is there anybodies base here. */
  1791.  
  1792. int
  1793. any_base_here(x, y)
  1794. int x, y;
  1795. {
  1796. /*    int utype = vtype(side_view(mside, x, y)); */
  1797.  
  1798.     return (0 /* utype != EMPTY && utype != UNSEEN && u_is_base(utype) */);
  1799. }
  1800. #endif
  1801.  
  1802. #if 0
  1803. /* Is there anybodies base here. */
  1804.  
  1805. int
  1806. neutral_base_here(x, y)
  1807. int x, y;
  1808. {
  1809.     int view = side_view(mside, x, y);
  1810.     int utype = vtype(view);
  1811.  
  1812.     return (utype != EMPTY && utype != UNSEEN &&
  1813.         u_is_base(utype) && vside_indep(view));
  1814.     return FALSE;
  1815. }
  1816. #endif
  1817.  
  1818. #if 0
  1819. /* Is there a base within the given range.  Generally range is small. */
  1820.  
  1821. int
  1822. base_nearby(unit,range)
  1823. Unit *unit;
  1824. int range;
  1825. {
  1826.     int x,y;
  1827.   
  1828.     return search_around(unit->x, unit->y, range, base_here, &x, &y, 1);
  1829. }
  1830. #endif
  1831.  
  1832. /* Is there a base within the given range.  Generally range is small. */
  1833.  
  1834. #if 0
  1835. int
  1836. any_base_nearby(unit,range)
  1837. Unit *unit;
  1838. int range;
  1839. {
  1840.     int x,y;
  1841.   
  1842.     return search_around(unit->x, unit->y, range, any_base_here, &x, &y, 1);
  1843. }
  1844. #endif
  1845.  
  1846. /* Is there a neutral base within the given range.  Generally range is
  1847.    small. */
  1848.  
  1849. #if 0
  1850. int
  1851. neutral_base_nearby(unit,range)
  1852. Unit *unit;
  1853. int range;
  1854. {
  1855.     int x,y;
  1856.   
  1857.     return search_around(unit->x, unit->y, range, neutral_base_here, &x, &y, 1);
  1858. }
  1859. #endif
  1860.  
  1861. int
  1862. occupant_could_capture(unit, u2)
  1863. Unit *unit;
  1864. int u2;
  1865. {
  1866.     Unit *occ;
  1867.  
  1868.     for_all_occupants(unit, occ)
  1869.       if (uu_capture(occ->type, u2) > 0)
  1870.     return TRUE;
  1871.     return FALSE;
  1872. }
  1873.  
  1874. /* Check to see if there is anyone around to capture. */
  1875.  
  1876. int
  1877. can_capture_neighbor(unit)
  1878. Unit *unit;
  1879. {
  1880.     int d, x, y;
  1881.     int view;
  1882.     Side *side2;
  1883.  
  1884.     for_all_directions(d) {
  1885.       if (interior_point_in_dir(unit->x, unit->y, d, &x, &y)) {
  1886.     view = unit_view(unit->side, x, y);
  1887.     if (view != UNSEEN && view != EMPTY) {
  1888.         side2 = side_n(vside(view));
  1889.         if (!allied_side(unit->side, side2)) {
  1890.         if (uu_capture(unit->type, vtype(view)) > 0) {
  1891.             /* need some other way to change move order quickly */
  1892.             return TRUE;
  1893.         }
  1894.         }
  1895.     }
  1896.       }
  1897.     }
  1898.     return FALSE;
  1899. }
  1900.  
  1901. /* check if our first occupant can capture something.  Doesn't look at
  1902.    other occupants. */
  1903.  
  1904. int
  1905. occupant_can_capture_neighbor(unit)
  1906. Unit *unit;
  1907. {
  1908.     Unit *occ = unit->occupant;
  1909.  
  1910.     if (occ != NULL && occ->act && occ->act->acp > 0 && occ->side == unit->side) {
  1911.     if (can_capture_neighbor(occ)) {
  1912.         return TRUE;
  1913.     }
  1914.     }
  1915.     return FALSE;
  1916. }
  1917.  
  1918. /* Find the closes unit, first prefering bases, and then transports. */
  1919.  
  1920. int
  1921. find_closest_unit(side, x0, y0, maxdist, pred, rxp, ryp)
  1922. Side *side;
  1923. int x0, y0, maxdist, (*pred)(), *rxp, *ryp;
  1924. {
  1925. #if 0    
  1926.     Unit *unit;
  1927.     int u, dist;
  1928.     int found = FALSE;
  1929.  
  1930.     for_all_unit_types(u) {
  1931.     if (u_is_base(u)) {
  1932.         for (unit = NULL /* side_strategy(side)->unitlist[u]*/; unit != NULL; unit = unit->mlist) {
  1933.         if (alive(unit) &&
  1934.             (dist = distance(x0, y0, unit->x, unit->y)) <= maxdist) {
  1935.             if ((*pred)(unit->x, unit->y)) {
  1936.             maxdist = dist - 1;
  1937.             *rxp = unit->x;  *ryp = unit->y;
  1938.             found = TRUE;
  1939.             }
  1940.         }
  1941.         }
  1942.     }
  1943.     }
  1944.     if (found) {
  1945.     return TRUE;
  1946.     }
  1947.     for_all_unit_types(u) {
  1948.     if (!u_is_base(u) && u_is_transport(u)) {
  1949.         for (unit = NULL /*side_strategy(side)->unitlist[u]*/; unit != NULL; unit = unit->mlist) {
  1950.         if (alive(unit)
  1951.             && distance(x0, y0, unit->x, unit->y) <= maxdist) {
  1952.             if ((*pred)(unit->x, unit->y)) {
  1953.             maxdist = dist - 1;
  1954.             *rxp = unit->x;  *ryp = unit->y;
  1955.             found = TRUE;
  1956.             }
  1957.         }
  1958.         }
  1959.     }
  1960.     }
  1961.     if (found) {
  1962.     return TRUE;
  1963.     }
  1964.     /* (What's the point of finding a non-base/non-transport?) */
  1965.     for_all_unit_types(u) {
  1966.     if (!u_is_base(u) && !u_is_transport(u)) {
  1967.         for (unit = NULL/*side_strategy(side)->unitlist[u]*/; unit != NULL; unit = unit->mlist) {
  1968.         if (alive(unit)
  1969.             && distance(x0, y0, unit->x, unit->y) <= maxdist) {
  1970.             if ((*pred)(unit->x, unit->y)) {
  1971.             maxdist = dist - 1;
  1972.             *rxp = unit->x;  *ryp = unit->y;
  1973.             found = TRUE;
  1974.             }
  1975.         }
  1976.         }
  1977.     }
  1978.     }
  1979.     if (found) {
  1980.     return TRUE;
  1981.     }
  1982. #endif
  1983.     return FALSE;
  1984. }
  1985.  
  1986. /* True if the given unit is a sort that can build other units. */
  1987.  
  1988. int
  1989. can_build(unit)
  1990. Unit *unit;
  1991. {
  1992.     int p;
  1993.  
  1994.     for_all_unit_types(p) {
  1995.     if (could_create(unit->type, p)) return TRUE;
  1996.     }
  1997.     return FALSE;
  1998. }
  1999.  
  2000. /* Test if unit can move out into adjacent cells. */
  2001.  
  2002. int
  2003. can_move(unit)
  2004. Unit *unit;
  2005. {
  2006.     int d, x, y;
  2007.  
  2008.     for_all_directions(d) {
  2009.       if (interior_point_in_dir(unit->x, unit->y, d, &x, &y)) {
  2010.         /* (should account for world-leaving options?) */
  2011.     if (could_move(unit->type, terrain_at(x, y))) return TRUE;
  2012.       }
  2013.     }
  2014.     return FALSE;
  2015. }
  2016.  
  2017. /* Returns the type of missing supplies. Not great routine if first */
  2018. /* material is a type of ammo. */
  2019.  
  2020. int
  2021. out_of_ammo(unit)
  2022. Unit *unit;
  2023. {
  2024.     int u = unit->type, r;
  2025.  
  2026.     for_all_material_types(r) {
  2027.     if (um_consumption_per_attack(u, r) > 0 && unit->supply[r] <= 0)
  2028.         return r;
  2029.     }
  2030.     return (-1);
  2031. }
  2032.  
  2033. #if 0
  2034. /* Someplace that we can definitely get supplies at. */
  2035.  
  2036. int
  2037. good_haven_p(side, x, y)
  2038. Side *side;
  2039. int x, y;
  2040. {
  2041.     Unit *unit = unit_at(x, y);
  2042.     int r;
  2043.     Task *route;
  2044.  
  2045.     if (unit != NULL) {
  2046.     if (allied_side(side, unit->side) && alive(unit) &&
  2047.         can_carry(unit, unit) && !might_be_captured(unit)) {
  2048.         for_all_material_types(r) {
  2049.         /* could also add in distance calculation to see how much we */
  2050.         /* really need. */
  2051.         if (unit->supply[r] < um_storage_x(unit->type, r)) {
  2052.             return FALSE;
  2053.         }
  2054.         }
  2055.     }
  2056.     } 
  2057.     return FALSE;
  2058. }
  2059. #endif
  2060.  
  2061. #if 0
  2062. /* See if the location has a unit that can take us in for refueling */
  2063. /* (where's the check for refueling ability?) */
  2064.  
  2065. /* Is doing the side-effect a good idea here? */
  2066.  
  2067. int
  2068. haven_p(unit, x, y)
  2069. Unit *unit;
  2070. int x, y;
  2071. {
  2072.     Unit *unit2 = unit_at(x, y);
  2073.     Task *route;
  2074.  
  2075.       return FALSE;
  2076. }
  2077. #endif
  2078.  
  2079. #if 0
  2080. /* See if the location has a unit that can repair us */
  2081.  
  2082. int
  2083. shop_p(unit, x, y)
  2084. Unit *unit;
  2085. int x, y;
  2086. {
  2087.     Unit *unit2 = unit_at(x, y);
  2088.     Task *route;
  2089.  
  2090.       return FALSE;
  2091. }
  2092. #endif
  2093.  
  2094. /* Check how long a unit can sit where it is */
  2095.  
  2096. int
  2097. survival_time(unit)
  2098. Unit *unit;
  2099. {
  2100.     int u = unit->type, m, least = 99999, rate, tmp;
  2101.     int t = terrain_at(unit->x, unit->y);
  2102.  
  2103.     for_all_material_types(m) {
  2104.     rate = (um_base_consumption(u, m)
  2105.         - (um_base_production(u, m) * ut_productivity(u, t)) / 100);
  2106.     if (rate > 0) {
  2107.         tmp = unit->supply[m];
  2108.         if (unit->act) {
  2109.         tmp += unit->act->actualmoves * um_consumption_per_move(u, m);
  2110.         }
  2111.         least = min(least, tmp / rate);
  2112.     }
  2113.     }
  2114.     return least;
  2115. }
  2116.  
  2117. long
  2118. regions_around(u, x, y, center)
  2119. int u, x, y;
  2120. int center;
  2121. {
  2122. }
  2123.  
  2124. int
  2125. usable_cell(unit, x, y)
  2126. Unit *unit;
  2127. int x, y;
  2128. {
  2129.     int u = unit->type;
  2130.     int view = unit_view(unit->side, x, y);
  2131.     
  2132.     return (((view == EMPTY) || view == UNSEEN ||
  2133.         (allied_side(side_n(vside(view)),unit->side) &&
  2134.          could_carry(vtype(view), u))) &&
  2135.            could_move(u, terrain_at(x, y)));
  2136. }
  2137.  
  2138. Task *explorechain;
  2139.  
  2140. int
  2141. explorable_cell(x, y)
  2142. int x, y;
  2143. {
  2144.     return (terrain_view(tmpside, x, y) == UNSEEN);
  2145. }
  2146.  
  2147. int
  2148. reachable_unknown(x, y)
  2149. int x, y;
  2150. {
  2151.     if (!inside_area(x, y)) return FALSE;
  2152.     if (terrain_view(tmpside, x, y) == UNSEEN) {
  2153.         if (adj_known_ok_terrain(x, y, tmpside, tmpunit->type)) {
  2154.         return TRUE;
  2155.     } else {
  2156.         return FALSE;
  2157.     }
  2158.     } else {
  2159.     return FALSE;
  2160.     }
  2161. }
  2162.  
  2163. /* Test whether the given location has an adjacent cell that is ok for
  2164.    the given type to be out in the open. */
  2165.  
  2166. int
  2167. adj_known_ok_terrain(x, y, side, u)
  2168. int x, y, u;
  2169. Side *side;
  2170. {
  2171.     int dir, x1, y1, t;
  2172.  
  2173.     if (!inside_area(x, y) || side == NULL) return FALSE;
  2174.     for_all_directions(dir) {
  2175.         if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
  2176.             if (terrain_view(side, x1, y1) == UNSEEN) continue;
  2177.             t = terrain_at(x1, y1);
  2178.             if (!terrain_always_impassable(u, t)) return TRUE;
  2179.         }
  2180.     }
  2181.     return FALSE;
  2182. }
  2183.  
  2184. /* Go to the nearest cell that we can see how to get to. */
  2185.  
  2186. int
  2187. explore_reachable_cell(unit, range)
  2188. Unit *unit;
  2189. int range;
  2190. {
  2191.     int x, y;
  2192.  
  2193.     if (g_see_all() || g_terrain_seen()) return FALSE;
  2194.     tmpunit = unit;
  2195.     tmpside = unit->side;
  2196.     DMprintf("%s searching within %d for cell to explore -", unit_desig(unit), range);
  2197.     if (search_around(unit->x, unit->y, range, reachable_unknown, &x, &y, 1)) {
  2198.     push_movenear_task(unit, x, y, 1);
  2199.     DMprintf("found one at %d,%d\n", x, y);
  2200.     return TRUE;
  2201.     }
  2202.     DMprintf("found nothing\n");
  2203.     return FALSE;
  2204. }
  2205.  
  2206. /* Check for any makers this unit should be capturing. */
  2207.  
  2208. int
  2209. should_capture_maker(unit)
  2210. Unit *unit;
  2211. {
  2212.     return 0;
  2213. }
  2214.  
  2215. /* Returns true if the given unit can't leave its cell for some reason. */
  2216.  
  2217. int
  2218. no_possible_moves(unit)
  2219. Unit *unit;
  2220. {
  2221.     int fx = unit->x, fy = unit->y, ut = unit->type;
  2222.     int d, x, y;
  2223.     int view;
  2224.     Side *side = unit->side;
  2225.  
  2226.     for_all_directions(d) {
  2227.     x = wrap(fx + dirx[d]);  y = limit(fy + diry[d]);
  2228.     view = unit_view(side, x, y);
  2229.     if (view == EMPTY) {
  2230.         if (could_move(ut, terrain_at(x, y)))
  2231.           return FALSE;
  2232.     } else if (enemy_side(side_n(vside(view)) , side)
  2233.            && could_hit(ut, vtype(view))) {
  2234.         return FALSE;
  2235.     } else if (could_carry(vtype(view), ut) &&
  2236.            allied_side(side_n(vside(view)), side))
  2237.       return FALSE;
  2238.     }
  2239.     return TRUE;
  2240. }
  2241.  
  2242. int
  2243. adj_known_passable(side, x, y, u)
  2244. Side *side;
  2245. int x, y, u;
  2246. {
  2247.     int dir;
  2248.  
  2249.     for_all_directions(dir) {
  2250.     if (unit_view(side, wrapx(x + dirx[dir]), y + diry[dir]) != UNSEEN
  2251.         && could_occupy(u, terrain_at(wrapx(x + dirx[dir]), y + diry[dir])))
  2252.       return TRUE;
  2253.     }
  2254.     return FALSE;
  2255. }
  2256.  
  2257. int
  2258. adj_obstacle(type, x, y)
  2259. int type, x, y;
  2260. {
  2261.     int d, x1, y1;
  2262.  
  2263.     for_all_directions(d) {
  2264.     x1 = wrap(x + dirx[d]);  y1 = limit(y + diry[d]);
  2265.     if (!could_move(type, terrain_at(x1, y1))) return TRUE;
  2266.     }
  2267.     return FALSE;
  2268. }
  2269.  
  2270. /* Estimate the usual number of turns to finish construction. */
  2271.  
  2272. int
  2273. normal_completion_time(u, u2)
  2274. int u, u2;
  2275. {
  2276.     if (u_acp(u) == 0 || uu_cp_per_build(u, u2) == 0)
  2277.       return (-1);
  2278.     return (u_cp(u2) - uu_creation_cp(u, u2)) /
  2279.       (uu_cp_per_build(u, u2) * u_acp(u));
  2280. }
  2281.  
  2282.  
  2283. /* True if anybody at all is on any adjacent cell. */
  2284.  
  2285. int
  2286. adj_unit(x, y)
  2287. int x, y;
  2288. {
  2289.     int d, x1, y1;
  2290.  
  2291.     for_all_directions(d) {
  2292.     if (interior_point_in_dir(x, y, d, &x1, &y1)) {
  2293.         if (unit_at(x1, y1)) return TRUE;
  2294.     }
  2295.     }
  2296.     return FALSE;
  2297. }
  2298.  
  2299. /* A unit runs low on supplies at the halfway point.  Formula is the same
  2300.    no matter how/if occupants eat transports' supplies. */
  2301.  
  2302. int
  2303. past_halfway_point(unit)
  2304. Unit *unit;
  2305. {
  2306.     int u = unit->type, m;
  2307.  
  2308.     for_all_material_types(m) {
  2309.     if (((um_base_consumption(u, m) > 0) || (um_consumption_per_move(u, m) > 0)) &&
  2310.         /* should check that the transport is adequate for */
  2311.         /* supplying the fuel */ 
  2312.         (unit->transport == NULL)) {
  2313.         if (2 * unit->supply[m] <= um_storage_x(u, m)) return TRUE;
  2314.     }
  2315.     }
  2316.     return FALSE;
  2317. }
  2318.  
  2319.  
  2320. /* This is the maximum distance from "home" that a unit can expect to get,
  2321.    travelling on its most hostile terrain type. */
  2322.  
  2323. int
  2324. operating_range_worst(u)
  2325. int u;
  2326. {
  2327.     int m, t, prod, range, worstrange = area.maxdim;
  2328.  
  2329.     for_all_material_types(m) {
  2330.         if (um_base_consumption(u, m) > 0) {
  2331.         for_all_terrain_types(t) {
  2332.             if (!terrain_always_impassable(u, t)) {
  2333.                 prod = (um_base_production(u, m) * ut_productivity(u, t)) / 100;
  2334.                 if (prod < um_base_consumption(u, m)) {
  2335.             range = um_storage_x(u, m) / (um_base_consumption(u, m) - prod);
  2336.             if (range < worstrange) worstrange = range;
  2337.             }
  2338.         }
  2339.         }
  2340.     }
  2341.     }
  2342.     return worstrange;
  2343. }
  2344.  
  2345. /* Same, but for best terrain. */
  2346.  
  2347. int
  2348. operating_range_best(u)
  2349. int u;
  2350. {
  2351.     int m, t, prod, range, tbestrange, tbest = 0, bestrange = 0;
  2352.  
  2353.     for_all_terrain_types(t) {
  2354.     if (!terrain_always_impassable(u, t)) {
  2355.         tbestrange = area.maxdim;
  2356.         for_all_material_types(m) {
  2357.         if (um_base_consumption(u, m) > 0) {
  2358.                 prod = (um_base_production(u, m) * ut_productivity(u, t)) / 100;
  2359.                 if (prod < um_base_consumption(u, m)) {
  2360.             range = um_storage_x(u, m) / (um_base_consumption(u, m) - prod);
  2361.             if (range < tbestrange) tbestrange = range;
  2362.             }
  2363.         }
  2364.         }
  2365.         if (tbestrange > bestrange) {
  2366.         bestrange = tbestrange;
  2367.         tbest = t;
  2368.         }
  2369.     }
  2370.     }
  2371.     return bestrange;
  2372. }
  2373.  
  2374. int
  2375. terrain_always_impassable(u, t)
  2376. int u, t;
  2377. {
  2378.     if (ut_vanishes_on(u, t))
  2379.       return TRUE;
  2380.     if (ut_wrecks_on(u, t))
  2381.       return TRUE;
  2382.     if (ut_mp_to_enter(u, t) > u_acp(u))
  2383.       return TRUE;
  2384.     return FALSE;
  2385. }
  2386.